package com.apestech.framework.dictionary.modul;

import com.apestech.framework.dictionary.DictUtil;
import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.util.StringUtil;
import com.apestech.framework.util.callback.SpiltStrCallback;

import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.Map;

/**
 * @author hup
 * @create 2018-08-24-10:53
 */
public class Table extends StringUtil {

    public class FieldText {
        private String id;
        private String text;

        public FieldText(JSONObject map){
            if(map==null) return;
            id=map.getString("id");
            text=map.getString("text");
        }

        public FieldText(String id, String text){
            this.id=id;
            this.text=text;
        }

        public String getId() {
            return id;
        }

        public String getText() {
            return text;
        }

        public void setId(String id) {
            this.id = id;
        }

        public void setText(String text) {
            this.text = text;
        }
    }

    public class Field {
        private int length;
        private int size;
        private String remarks;
        private String oremarks;
        private String className;
        private String typeName;
        private String fId;
        private String fTab;
        private String columnDef;
        private String notNull;
        private ArrayList<FieldText> list;
        private String treeTable;
        private String treeId;
        private String treePId;
        private String dbType;
        private JSONObject fmap;

        public Field(){}

        public Field(JSONObject map) throws Exception {
            length=map.getInteger("length");
            size=map.getInteger("size");
            remarks=map.getString("remarks");
            oremarks=map.getString("oremarks");
            className=map.getString("className");
            typeName=map.getString("typeName");
            fId=map.getString("fId");
            fTab=map.getString("fTab");
            columnDef=map.getString("columnDef");
            notNull=map.getString("notNull");
            treeTable=map.getString("treeTable");
            treeId=map.getString("treeId");
            treePId=map.getString("treePId");
            dbType=map.getString("dbType");

            if(dbType==null){
                dbType=map.getString("typeName");
            }
            if("VARCHAR2".equals(dbType)){
                dbType=dbType+"("+map.getString("length")+" CHAR)";
            }
            fmap= (JSONObject) map.get("fmap");
            JSONArray t=JSON.toJSONArray(map.get("list"));
            if(t!=null){
                int len=t.size();
                if(len>0){
                    list=new ArrayList<>();
                }
                for(int i=0; i<len; i++){
                    list.add(new FieldText(t.get(i)));
                };
            }
        }

        public JSONObject getJSON(String field, Table table){
            if(fmap==null){
                fmap=new JSONObject();
                fmap.put("type", dbType);
                if("1".equals(notNull)){
                    fmap.put("notNull", "true");
                }
                if(table.getPkKey()!=null){
                    if((";"+table.getPkKey().getPkColumn()+";").indexOf(";"+field+";")>=0){
                        fmap.put("isKey", "true");
                    }
                }
                if(columnDef!=null){
                    fmap.put("defaultValue", columnDef);
                }
                if(table.getPkFKey()!=null){
                    if(table.getPkFKey().get(field)!=null){
                        fmap.put("foreignTab", table.getPkFKey().getPkTableName(field));
                        fmap.put("foreignKey", table.getPkFKey().getColumnName(field));
                    }
                }
                fmap.put("comment", oremarks);
            }
            return fmap;
        }

        public int getLength() {
            return length;
        }

        public int getSize() {
            return size;
        }

        public String getRemarks() {
            return remarks;
        }

        public String getOremarks() {
            return oremarks;
        }

        public String getClassName() {
            return className;
        }

        public String getTypeName() {
            return typeName;
        }

        public String getfId() {
            return fId;
        }

        public String getfTab() {
            return fTab;
        }

        public String getColumnDef() {
            return columnDef;
        }

        public String getNotNull() {
            return notNull;
        }

        public void setLength(int length) {
            this.length = length;
        }

        public void setSize(int size) {
            this.size = size;
        }

        public void setRemarks(String remarks) {
            this.remarks = remarks;
            if(oremarks==null) oremarks=remarks;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public void setTypeName(String typeName) {
            this.typeName = typeName;
        }

        public void setfId(String fId) {
            this.fId = fId;
        }

        public void setfTab(String fTab) {
            this.fTab = fTab;
        }

        public void setColumnDef(String columnDef) {
            this.columnDef = columnDef;
        }

        public void setNotNull(String notNull) {
            this.notNull = notNull;
        }

        public void setList(ArrayList<FieldText> list) {
            this.list = list;
        }

        public void addList(String id, String text){
            if(list==null){
                list=new ArrayList<FieldText>();
            }
            list.add(new FieldText(id, text));
        }

        public ArrayList<FieldText> getList() {
            return list;
        }

        public String getTreeTable() {
            return treeTable;
        }

        public void setTreeTable(String treeTable) {
            this.treeTable = treeTable;
        }

        public String getTreeId() {
            return treeId;
        }

        public void setTreeId(String treeId) {
            this.treeId = treeId;
        }

        public String getTreePId() {
            return treePId;
        }

        public void setTreePId(String treePId) {
            this.treePId = treePId;
        }

        public String getDbType() {
            return dbType;
        }

        public void setDbType(String dbType) {
            this.dbType = dbType;
        }
    }

    public class ExField{
        private String name;
        private String type;
        private int size;

        public ExField(){}

        public ExField(JSONObject map) throws Exception {
            if(map==null) return;
            name=map.getString("name");
            type=map.getString("type");
            if(map.get("size")!=null){
                size=map.getInteger("size");
            }
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }
    }

    private String column;
    private String remarks;
    private String dateColumn;
    private String numColumn;
    private String intColumn;
    private JSONObject field=new JSONObject();
    private PrimaryKey pkKey;
    private ImportedKey pkFKey;
    private JSONObject exField;
    private boolean isTree=false;
    private String treeId;
    private String treePid;
    private String[] collist;
    private String[] remarklist;
    private JSONObject index;
    private String tabname;
    private String fkField="";
    private ArrayList<String> columnlist;

    public Table(JSONObject map) throws Exception {
        column=map.getString("column");
        remarks=map.getString("remarks");
        dateColumn=map.getString("dateColumn");
        numColumn=map.getString("numColumn");
        intColumn=map.getString("intColumn");

        if(map.get("isTree")!=null){
            isTree=map.getBoolean("isTree");
        }
        treeId=map.getString("treeId");
        treePid=map.getString("treePid");
        collist= castToAString((ArrayList<String>) map.get("collist"));
        remarklist= castToAString((ArrayList<String>) map.get("remarklist"));
        index=JSON.toJSON(map.get("index"));
        tabname=map.getString("tabname");
        columnlist= (ArrayList<String>) map.get("columnlist");

        JSONObject fieldmap=JSON.toJSON(map.get("field"));
        if(fieldmap!=null){
            field=new JSONObject();
            for(String key:fieldmap.getKeylist()){
                field.put(key, new Field(JSON.toJSON(fieldmap.get(key))));
            }
        }

        if(map.get("pkKey")!=null){
            pkKey=new PrimaryKey(JSON.toJSON(map.get("pkKey")));
        }
        if(map.get("pkFKey")!=null){
            JSONObject p=JSON.toJSON(map.get("pkFKey"));
            pkFKey=new ImportedKey(p);
            fkField="";
            for(String s: pkFKey.getFieldList()){
                fkField=fkField+","+s;
            }
        }

        JSONObject exfieldmap=JSON.toJSON(map.get("exField"));
        if(exfieldmap!=null){
            exField=new JSONObject();
            for(String key:exfieldmap.getKeylist()){
                exField.put(key, new ExField(JSON.toJSON(exfieldmap.get(key))));
            }
        }
    }

    public Table(String tabname){
        this.tabname=tabname;
    }

    public String getColumn() {
        return column;
    }

    public void setColumn(String column) {
        this.column = column;
    }

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public String getDateColumn() {
        return dateColumn;
    }

    public void setDateColumn(String dateColumn) {
        this.dateColumn = dateColumn;
    }

    public String getNumColumn() {
        return numColumn;
    }

    public void setNumColumn(String numColumn) {
        this.numColumn = numColumn;
    }

    public String getIntColumn() {
        return intColumn;
    }

    public void setIntColumn(String intColumn) {
        this.intColumn = intColumn;
    }

    public PrimaryKey getPkKey() {
        return pkKey;
    }

    public ImportedKey getPkFKey() {
        return pkFKey;
    }

    public void setField(JSONObject field) {
        this.field = field;
    }

    public JSONObject getField() {
        return field;
    }

    public Field getField(String fieldName){
        Object f=field.get(fieldName);
        if(f==null){
            field.put(fieldName, new Field());
            f=field.get(fieldName);
        }
        return (Field) f;
    }

    public void setRemarks(String fieldName, String remarks) {
        Field f=getField(fieldName);
        f.setRemarks(remarks);
        field.put(fieldName, f);
    }

    public int getSize(String fieldName) {
        return getField(fieldName).getSize();
    }

    public int getLength(String fieldName) {
        return getField(fieldName).getLength();
    }

    public String getRemarks(String fieldName) {
        return getField(fieldName).getRemarks();
    }

    public String getOremarks(String fieldName) {
        return getField(fieldName).getOremarks();
    }

    public String getClassName(String fieldName) {
        return getField(fieldName).getClassName();
    }

    public String getTypeName(String fieldName) {
        return getField(fieldName).getTypeName();
    }

    public String getfId(String fieldName) {
        return getField(fieldName).getfId();
    }

    public String getfTab(String fieldName) {
        return getField(fieldName).getfTab();
    }

    public String getColumnDef(String fieldName) {
        return getField(fieldName).getColumnDef();
    }

    public String getNotNull(String fieldName) {
        return getField(fieldName).getNotNull();
    }

    public ArrayList<FieldText> getList(String fieldName) {
        return getField(fieldName).getList();
    }

    public JSONObject getIndex() {
        return index;
    }

    public void setIndex(JSONObject index) {
        this.index = index;
    }

    public void addList(String fieldName, String id, String text){
        getField(fieldName).addList(id, text);
    }

    public String addField(JSONObject map) throws Exception {
        if(map==null || map.size()==0) return null;
        String fieldName=map.getString("COLUMN_NAME");
        addFieldDetail(fieldName, map);
        return fieldName;
    }

    public void addField(ResultSetMetaData rsmd) throws Exception{
        int count=rsmd.getColumnCount();
        String col="";
        String dateCol="";
        String numCol="";
        String intCol="";
        for(int i=0; i<count; i++){
            String fieldName=rsmd.getColumnName(i+1);
            String nullable="0";
            if(rsmd.isNullable(i+1)==1) nullable = "1";
            int len=rsmd.getPrecision(i+1);
            JSONObject map=DictUtil.getReslutData(fieldName, null, rsmd.getColumnTypeName(i+1),null,
                    nullable, len, len, rsmd.getScale(i+1));
            addFieldDetail(fieldName, map);
            if(!"".equals(col)){
                col=col+",";
            }
            col=col+fieldName;
            String typeName=map.getString("TYPE_NAME");
            if(typeName.indexOf("DATE")>=0 || typeName.indexOf("TIME")>=0){
                if(!"".equals(dateCol)){
                    dateCol=dateCol+",";
                }
                dateCol=dateCol+fieldName;
            } else if(typeName.indexOf("NUMBER")>=0){
                if(map.getInteger("SIZE")>0){
                    if(!"".equals(numCol)){
                        numCol=numCol+",";
                    }
                    numCol=numCol+fieldName;
                } else {
                    if(!"".equals(intCol)){
                        intCol=intCol+",";
                    }
                    intCol=intCol+fieldName;
                }
            }
        }
        setColumn(col);
        setDateColumn(dateCol);
        setNumColumn(numCol);
        setIntColumn(intCol);
    }

    private void addFieldDetail(String fieldName, JSONObject map) throws Exception {
        Field f=getField(fieldName);
        if(f.getfId()==null) f.setfId(map.getString("FID"));
        if(f.getfTab()==null) f.setfTab(map.getString("FTAB"));
        f.setRemarks(map.getString("REMARKS"));
        f.setClassName(map.getString("CLASSNAME"));
        f.setTypeName(map.getString("TYPE_NAME"));
        f.setColumnDef(map.getString("COLUMN_DEF"));
        f.setNotNull(map.getString("NOTNULL"));
        f.setDbType(map.getString("DB_TYPE"));
        if(f.getDbType()==null){
            f.setDbType(map.getString("TYPE_NAME"));
        }

        if(map.get("LENGTH")!=null){
            f.setLength(map.getInteger("LENGTH"));
        }
        if(map.get("SIZE")!=null){
            f.setSize(map.getInteger("SIZE"));
        }
        field.put(fieldName, f);
    }

    public void setPkKeyfromJSON(JSONObject map) {
        if(map==null || map.size()==0) return;
        pkKey=new PrimaryKey();
        pkKey.setPkName(map.getString("PK_NAME"));
        pkKey.setTableName(map.getString("TABLE_NAME"));
        pkKey.setPkColumn(map.getString("PK_COLUMN"));
    }

    private JSONObject getFKMap(JSONObject map) throws Exception {
        JSONObject fkmap=new JSONObject();
        ArrayList<String> klist=map.getKeylist();
        int len=map.size();
        for(int i=0; i<len; i++){
            String k=klist.get(i);
            JSONObject m= JSON.toJSON(map.get(k));
            String fkname=m.getString("FK_NAME");
            String col=m.getString("PKCOLUMN_NAME");
            //将外键字段和数据表字段多个关系做关联操作，这里fkmap的值应为json格式
            FieldText f=new FieldText(k, col);
            FieldText id= (FieldText) fkmap.get(fkname);
            if(id==null) id=f;
            else {
                id.setId(id.getId()+","+k);
                id.setText(id.getText()+","+col);
            }
            fkmap.put(fkname, id);
        }
        return fkmap;
    }

    public void setPkFKeyFromJSON(String tableName, JSONObject map) throws Exception {
        if(map==null || map.size()==0) return;
        final boolean[] flag = {false};
        pkFKey=new ImportedKey();
        JSONObject fkmap=getFKMap(map);
        ArrayList<String> klist=map.getKeylist();
        int len=klist.size();
        for(int i=0; i<len; i++){
            String k=klist.get(i);
            JSONObject m= new JSONObject((Map) map.get(k));
            String tab=m.getString("PKTABLE_NAME");
            String col=m.getString("PKCOLUMN_NAME");
            String fkname=m.getString("FK_NAME");
            FieldText ckey= (FieldText) fkmap.get(fkname);
            if(ckey!=null){
                fkField=fkField+","+k;
                pkFKey.add(k, ckey.getId(), tab, ckey.getText(), fkname);
                fkmap.remove(fkname);
            }
            execSplitStr(k, ",", new SpiltStrCallback() {
                @Override
                public void exec(String id) throws Exception {
                    Field f=getField(id);
                    f.setfTab(tab);
                    f.setfId(col);
                    String treeTable=m.getString("TREE_TABLE");
                    if(tableName.equals(tab)){
                        if(!flag[0]){
                            isTree=true;
                            treeId=col;
                            treePid=id;
                            flag[0] =true;
                        } else {
                            isTree=false;
                            treeId=null;
                            treePid=null;
                        }
                    } else {
                        f.setTreeTable(treeTable);
                        f.setTreeId(m.getString("TREE_ID"));
                        f.setTreePId(m.getString("TREE_PID"));
                    }
                    field.put(id, f);
                }
            });
        }
    }

    public int size(){
        if(field==null) return 0;
        return field.size();
    }

    private ExField getExField(String exName, String fieldName) throws Exception {
        if(exField==null) exField=new JSONObject();
        if(exField.get(exName)==null) exField.put(exName, new JSONObject());
        JSONObject efield=exField.getJSONObject(exName);
        Object f=efield.get(fieldName);
        if(f==null){
            efield.put(fieldName, new ExField());
            f=efield.get(fieldName);
        }
        return (ExField) f;
    }

    public String getExName(String exName, String fieldName) throws Exception {
        return getExField(exName, fieldName).getName();
    }

    public void setExName(String exName, String fieldName, String name) throws Exception {
        ExField f=getExField(exName, fieldName);
        f.setName(name);
        exField.put(fieldName, f);
    }

    public void setExType(String exName, String fieldName, String type) throws Exception {
        ExField f=getExField(exName, fieldName);
        f.setType(type);
        exField.put(fieldName, f);
    }

    public void setExSize(String exName, String fieldName, int size) throws Exception {
        ExField f=getExField(exName, fieldName);
        f.setSize(size);
        exField.put(fieldName, f);
    }

    public boolean isTree() {
        return isTree;
    }

    public void setTree(boolean tree) {
        isTree = tree;
    }

    public String getTreeTable(String fieldName) {
        return getField(fieldName).getTreeTable();
    }

    public String getTreeId(String fieldName) {
        return getField(fieldName).getTreeId();
    }

    public String getTreePId(String fieldName) {
        return getField(fieldName).getTreePId();
    }

    public String getDbType(String fieldName) {
        return getField(fieldName).getDbType();
    }

    public JSONObject getFieldJson(String fieldName) {
        return getField(fieldName).getJSON(fieldName, this);
    }

    public String getFieldByRemark(String remark){
        if(collist==null){
            collist=column.split(",");
            remarklist=remarks.split(",");
        }
        int len=collist.length;
        for(int i=0; i<len; i++){
            if(remark.equals(remarklist[i])){
                return collist[i];
            }
        }
        return null;
    }

    public ArrayList<String> getColumnList() throws Exception {
        if(columnlist==null){
            columnlist=new ArrayList<>();
            if(column!=null){
                execSplitStr(column, ",", new SpiltStrCallback() {
                    @Override
                    public void exec(String id) throws Exception {
                        if(!"".equals(id.trim())){
                            columnlist.add(id);
                        }
                    }
                });
            }
        }
        return columnlist;
    }

    public boolean isField(String field){
        return (","+column+",").indexOf(","+field+",")>=0;
    }

    public String getTabname() {
        return tabname;
    }

    public boolean isFkField(String field){
        return (","+fkField+",").indexOf(","+field+",")>=0;
    }


}
